package bag

import (
	"encoding/json"
	"math/rand"
	"sanguo/node/common/GlobalConstData"
	table_Soul "sanguo/node/table/excel/table/Soul"
	table_SoulEnchant "sanguo/node/table/excel/table/SoulEnchant"
	table_SoulRandAttr "sanguo/node/table/excel/table/SoulRandAttr"
	table_SoulRandCount "sanguo/node/table/excel/table/SoulRandCount"
	table_SoulStar "sanguo/node/table/excel/table/SoulStar"
	table_SoulUpStar "sanguo/node/table/excel/table/SoulUpStar"
	cs_message "sanguo/protocol/cs/message"

	"github.com/golang/protobuf/proto"
)

type SoulAttr struct {
	Id  int32
	Val int32
}

//武魂
type Soul struct {
	SoulId       uint64 //实例id
	ConfigId     int32  //配置id
	IsEquip      bool   //是否已装备
	StarLevel    int32  //星级
	EnchantLevel int32  //强化等级
	SoulPos      int32
	SoulExp      int32 //武魂升星当前拥有的经验

	//随机属性
	SoulAttrs map[int32]*SoulAttr
}

type RoleSoul struct {
	soulList  map[uint64]*Soul
	soulDirty map[uint64]bool
	dbDirty   bool
}

func FuncNewSoul(soulId uint64, configId int32) *Soul {
	return newSoul(soulId, configId)
}

func newSoul(soulId uint64, configId int32) *Soul {
	soul := &Soul{
		SoulId:       soulId,
		ConfigId:     configId,
		IsEquip:      false,
		StarLevel:    int32(0), //星级
		EnchantLevel: int32(0), //强化等级
		SoulPos:      newSoulPos(configId),
		SoulExp:      int32(0),
		SoulAttrs:    map[int32]*SoulAttr{},
	}
	soul.newSoulAttrCount()
	return soul
}

//给武魂随机一个装备武器的孔位
func newSoulPos(configId int32) int32 {
	//读表
	soulDef := table_Soul.Table_.IDMap[configId]
	if soulDef == nil {
		return 0
	}

	LockPos := map[int32]bool{}    //不可以随机的位置
	UnLockPos := map[int32]int32{} //可以随机的位置

	//存储不可随机的位置
	for _, v := range soulDef.LackHole {
		LockPos[v.LackPos] = true
	}

	//将可以随机的位置存到map中
	var key int32 = 0
	for pos := int32(1); pos <= int32(GlobalConstData.SoulMaxCount); pos++ {
		if _, ok := LockPos[pos]; !ok {
			UnLockPos[key] = pos
			key++
		}
	}

	randKey := rand.Int31n(int32(len(UnLockPos)))
	return UnLockPos[randKey]
}

func (this *Soul) newSoulAttrCount() {
	//读表 随机属性条数
	soulDef := table_Soul.Table_.IDMap[this.ConfigId]
	countDef := table_SoulRandCount.Table_.RarityMap[soulDef.Rarity]
	var count int32 = 0 //初始化条数
	p := rand.Int31n(10000) + 1
	var pp_ int32 = 0 //读表的概率累加值
	for i, v := range countDef.RandCount {
		pp_ += v.Prob
		if p <= pp_ {
			count = int32(i) + 1 //表的数组下标从0开始
			break
		}
	}

	rAttr := map[int32]bool{} //存储已初始化的属性
	this.InitSoulAttr(count, rAttr)
}

//初始化武魂的随机属性
func (this *Soul) InitSoulAttr(count int32, rAttr map[int32]bool) {
	soulDef := table_Soul.Table_.IDMap[this.ConfigId]

	//根据武魂 位置,阶数 计算随机属性的ID
	id := this.SoulPos*100 + soulDef.Order
	soulAttrDef := table_SoulRandAttr.Table_.IDMap[id]
	if soulAttrDef == nil {
		return
	}

	var totalProp int32 = 0 //存储可随机属性的概率总值
	var rCount int32 = 0    //初始化条数计数

	//初始化武魂随机属性
	for rCount < count {
		totalProp = 0
		for i, v := range soulAttrDef.RandAttr {
			if _, ok := rAttr[int32(i)+1]; !ok {
				totalProp += v.Prob
			}
		}

		var index int32 = 0 //属性枚举值
		p := rand.Int31n(totalProp) + 1
		var pp_ int32 = 0 //读表的概率累加值
		for i, v := range soulAttrDef.RandAttr {
			if _, ok := rAttr[int32(i)+1]; !ok {
				pp_ += v.Prob
				if p <= pp_ {
					index = int32(i)
					break
				}
			}
		}

		min := soulDef.RandAttr[index].Min
		max := soulDef.RandAttr[index].Max
		var vv int32 //属性值
		if max-min != 0 {
			vv = rand.Int31n(max-min+1) + min
		} else {
			vv = min
		}

		//表中的数组是从0开始，但是武魂属性从1开始 0即是1
		this.SoulAttrs[index+1] = &SoulAttr{
			Id:  index + 1,
			Val: vv,
		}

		rAttr[index+1] = true
		rCount++
	}

}

func (this *Soul) GetSoulId() uint64 {
	return this.SoulId
}

//镶嵌武魂
func (this *RoleSoul) EquipSoul(soul *Soul) bool {
	if soul.IsEquip {
		return false
	}
	soul.IsEquip = true

	this.SetDirtyFlag()
	this.soulDirty[soul.SoulId] = true
	return true
}

//卸下武魂
func (this *RoleSoul) DemountSoul(soul *Soul) bool {
	if !soul.IsEquip {
		return false
	}
	soul.IsEquip = false

	this.SetDirtyFlag()
	this.soulDirty[soul.SoulId] = true
	return true
}

//武魂强化
func (this *RoleSoul) SoulUpLevel(soul *Soul, useProtection bool) bool {
	/*
	*概率强化，每个强化等级有对应的强化成功率，以及失败惩罚
	 */

	SEDef := table_SoulEnchant.Table_.EnchantLevelMap[soul.EnchantLevel+1]
	if SEDef == nil {
		return false
	}

	p := rand.Int31n(10000) + 1
	if p > SEDef.Prob {
		if useProtection {
			return false
		}
		soul.EnchantLevel -= SEDef.Punishment
		if soul.EnchantLevel < 0 {
			soul.EnchantLevel = 0
		}

		this.SetDirtyFlag()
		this.soulDirty[soul.SoulId] = true
		return false
	}

	soul.EnchantLevel += 1

	this.SetDirtyFlag()
	this.soulDirty[soul.SoulId] = true
	return true
}

//武魂升星 吞噬橙色武魂累计经验升星  后一个吞噬前一个
func (this *RoleSoul) SoulUpStar(fromSoulIDs []uint64, toSoulID uint64) {

	addExp := int32(0)
	for _, fromSoulID := range fromSoulIDs {
		fromSoul := this.GetSoul(fromSoulID)
		fromDef := table_Soul.Table_.IDMap[fromSoul.ConfigId]
		fromID := fromDef.Rarity*100 + fromDef.Order
		fromUp := table_SoulUpStar.Table_.IDMap[fromID]
		addExp += fromUp.Exp

		delete(this.soulList, fromSoulID)

		this.SetDirtyFlag()
		this.soulDirty[fromSoulID] = true
	}

	toSoul := this.GetSoul(toSoulID)
	soulDef := table_Soul.Table_.IDMap[toSoul.ConfigId]
	toID := soulDef.Rarity*100 + soulDef.Order
	soulUp := table_SoulUpStar.Table_.IDMap[toID]

	if toSoul.StarLevel < GlobalConstData.StarMaxLevel {
		toSoul.SoulExp += addExp
		NextStarNeedExp := soulUp.NeedExps[toSoul.StarLevel].NeedExp
		for toSoul.StarLevel < GlobalConstData.StarMaxLevel && toSoul.SoulExp >= NextStarNeedExp {
			toSoul.StarLevel++
			toSoul.SoulExp -= NextStarNeedExp
			if toSoul.StarLevel < GlobalConstData.StarMaxLevel {
				NextStarNeedExp = soulUp.NeedExps[toSoul.StarLevel].NeedExp
			} else {
				toSoul.SoulExp = 0
			}

			//升星后 随机属性小于5条加一条随机属性 随机属性等于5条随机属性加
			if len(toSoul.SoulAttrs) < 5 {
				rAttr := map[int32]bool{}
				for _, v := range toSoul.SoulAttrs {
					rAttr[v.Id] = true
				}
				toSoul.InitSoulAttr(int32(1), rAttr)
			} else {
				//武魂的星级属性
				ssId := toSoul.StarLevel*100 + soulDef.Order
				SSDef := table_SoulStar.Table_.IDMap[ssId]
				if SSDef != nil {
					for _, v := range toSoul.SoulAttrs {
						//max := soulDef.RandAttr[v.Id].Max
						v.Val += SSDef.SoulAttr[v.Id-1].AddAttr
						//if v.Val > max {
						//	v.Val = max
						//}
					}
				}

			}
		}

		this.SetDirtyFlag()
		this.soulDirty[toSoulID] = true
	}
}

//强化转移 从前一个转移到后一个 转移强化等级
func (this *RoleSoul) SoulMoveLevel(fromSoul, toSoul *Soul) bool {

	toSoul.EnchantLevel = fromSoul.EnchantLevel
	fromSoul.EnchantLevel = 0
	//delete(this.soulList, fromSoul.SoulId)

	this.SetDirtyFlag()
	this.soulDirty[fromSoul.SoulId] = true
	this.soulDirty[toSoul.SoulId] = true
	return true
}

func (this *RoleSoul) GetSoul(soulId uint64) *Soul {
	return this.soulList[soulId]
}

//添加武魂
func (this *RoleSoul) AddSoul(soul *Soul) {
	_, ok := this.soulList[soul.SoulId]
	if ok {
		return
	} else {
		this.soulList[soul.SoulId] = soul
	}

	this.SetDirtyFlag()
	this.soulDirty[soul.SoulId] = true
}

//获取武魂列表
func (this *RoleSoul) GetSoulList() []*Soul {
	souls := []*Soul{}
	for _, v := range this.soulList {
		souls = append(souls, v)
	}
	return souls
}

//打包武魂
func (this *RoleSoul) PackAllSoul() []*cs_message.Soul {
	ret := []*cs_message.Soul{}
	for _, v := range this.soulList {
		soulDef := table_Soul.Table_.IDMap[v.ConfigId]
		soul := &cs_message.Soul{
			SoulId:       proto.Uint64(v.SoulId),
			ConfigId:     proto.Int32(v.ConfigId),
			IsEquip:      proto.Bool(v.IsEquip),
			Order:        proto.Int32(soulDef.Order),
			StarLevel:    proto.Int32(v.StarLevel),
			EnchantLevel: proto.Int32(v.EnchantLevel),
			SoulPos:      proto.Int32(v.SoulPos),
			SoulExp:      proto.Int32(v.SoulExp),
			IsRemove:     proto.Bool(false),
		}
		for _, sAttr := range v.SoulAttrs {
			soulAttr := &cs_message.SoulAttr{
				Id:  proto.Int32(sAttr.Id),
				Val: proto.Int32(sAttr.Val),
			}
			soul.SoulAttrs = append(soul.SoulAttrs, soulAttr)
		}
		ret = append(ret, soul)
	}
	return ret
}

func (this *RoleSoul) GetSoulDirtyLength() int {
	return len(this.soulDirty)
}

func (this *RoleSoul) PackSoulModify() []*cs_message.Soul {

	ret := []*cs_message.Soul{}
	for id, b := range this.soulDirty {
		if b {
			delete(this.soulDirty, id)
			v := this.soulList[id]

			if v == nil {
				soul := &cs_message.Soul{
					SoulId:   proto.Uint64(id),
					IsRemove: proto.Bool(true),
				}
				ret = append(ret, soul)
			} else {
				soulDef := table_Soul.Table_.IDMap[v.ConfigId]
				soul := &cs_message.Soul{
					SoulId:       proto.Uint64(v.SoulId),
					ConfigId:     proto.Int32(v.ConfigId),
					IsEquip:      proto.Bool(v.IsEquip),
					Order:        proto.Int32(soulDef.Order),
					StarLevel:    proto.Int32(v.StarLevel),
					EnchantLevel: proto.Int32(v.EnchantLevel),
					SoulPos:      proto.Int32(v.SoulPos),
					SoulExp:      proto.Int32(v.SoulExp),
					IsRemove:     proto.Bool(false),
				}
				for _, sAttr := range v.SoulAttrs {
					soulAttr := &cs_message.SoulAttr{
						Id:  proto.Int32(sAttr.Id),
						Val: proto.Int32(sAttr.Val),
					}
					soul.SoulAttrs = append(soul.SoulAttrs, soulAttr)
				}
				ret = append(ret, soul)
			}
		}
	}

	return ret
}

func (this *RoleSoul) PackJson(fields map[string]interface{}) {
	if this.dbDirty {
		jsonStr, err := json.Marshal(this.soulList)
		if nil == err {
			fields["soul"] = jsonStr
		}
	}
}

func (this *RoleSoul) IsDirty() bool {
	return this.dbDirty

}

func (this *RoleSoul) SetDirtyFlag() {
	this.dbDirty = true
}

func (this *RoleSoul) ClearDirtyFlag() {
	this.dbDirty = false
}

func (this *RoleSoul) Init(souls map[uint64]*Soul) {
	this.soulList = souls
	this.soulDirty = map[uint64]bool{}
	this.dbDirty = false
}
